﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using CardGenerator.Annotations;

namespace CardGenerator.UI.Pages;

public class DictionaryBasedDataSource
{
    public static readonly DependencyProperty DictionaryDataSourceProperty = DependencyProperty.RegisterAttached(
        "DictionaryDataSource",
        typeof(ObservableCollection<Dictionary<String, String>>), 
        typeof(DictionaryBasedDataSource), 
        new FrameworkPropertyMetadata(PropertyChangedCallback));
    private static Dictionary<Object, DependencyObject> _newValues = new();
    private static void PropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var old = (e.OldValue as ObservableCollection<Dictionary<String, String>>);
        if (old != null)
        {
            old.CollectionChanged -= OnCollectionChanged;
            _newValues.Remove(old);
        }
        (e.NewValue as ObservableCollection<Dictionary<String, String>>).CollectionChanged += OnCollectionChanged;
        _newValues[e.NewValue] = d;
    }

    private static void OnCollectionChanged(object? sender, NotifyCollectionChangedEventArgs e)
    {
        var self = sender as ObservableCollection<Dictionary<String, String>>;
        var grid = _newValues[self] as DataGrid;
        grid.Items.Clear();
        if (self.Count == 0) return;
        if (self.First().Count == 0) return;
        grid.Columns.Clear();
        foreach (var key in self.First().Keys)
        {
            grid.Columns.Add(new DataGridTextColumn
            {
                Header = key,
                Binding = new Binding(key),
                Width = DataGridLength.SizeToCells,
            });
        }
        
        foreach (var row in self)
        {
            grid.Items.Add(new DataRow {UnderlyingData = row});
        }
    }

    public static ObservableCollection<Dictionary<String, String>> GetDictionaryDataSource(DataGrid dataGrid)
    {
        return dataGrid.GetValue(DictionaryDataSourceProperty) as ObservableCollection<Dictionary<String, String>>;
    }

    public static void SetDictionaryDataSource(DataGrid dataGrid, ObservableCollection<Dictionary<String, Object>> data)
    {
        dataGrid.SetValue(DictionaryDataSourceProperty, data);
    }
}

internal class RowDescriptor : PropertyDescriptor
{
    public override Type ComponentType
    {
        get => typeof(DataRow);
    }
    public override bool IsReadOnly
    {
        get => true;
    }
    public override Type PropertyType
    {
        get => typeof(String);
    }
    

    public override bool CanResetValue(object component)
    {
        return false;
    }

    public override object? GetValue(object? component)
    {
        return (component as DataRow)[this.Name];
    }

    public override void ResetValue(object component)
    {
        throw new NotImplementedException();
    }

    public override void SetValue(object? component, object? value)
    {
        (component as DataRow)[this.Name] = value?.ToString();
    }

    public override bool ShouldSerializeValue(object component)
    {
        return false;
    }

    public RowDescriptor([NotNull] string name) : base(name, Array.Empty<Attribute>())
    {
    }
}
internal class DataRow : CustomTypeDescriptor
{
    public Dictionary<String, String> UnderlyingData { get; set; }

    public String this[String name]
    {
        get
        {
            return UnderlyingData[name] ?? "";
        }
        set
        {
            UnderlyingData[name] = value;
        }
    }

    public override PropertyDescriptorCollection GetProperties()
    {
        return new PropertyDescriptorCollection(this.UnderlyingData.Keys.Select(it => new RowDescriptor(it)).ToArray());
    }
}